-module(es_db).
-export([
    get_identity/1,
    %%get_links/2,
    %%update_links/3
    test_add_link/3,
    test_add_link/4,
    get_oldest_links/1,
    test/0,
    intersection/2,
    contains/2,
    split/1,
    add_links/2
    ]).

-define(PORT, "5984").
-define(HOST, "127.0.0.1").
-define(DATABASE, "erlysocial").

get_oldest_links(Num) ->
    ecouch:start(temporary,{?HOST,?PORT}),%% Un-hardcode me.
    View = io_lib:format("_view/date_updated/oldest/?count=~w",[Num]),
    Response = ecouch:doc_get(?DATABASE,View),
    case Response of
        {error, Reason} -> {error, Reason};
        {ok, Obj} ->
            Rows = object:get_value(Obj, "rows"),
            Links = object:get_value_from_list(Rows, "value"),
            update_dates(Links),
            Links
    end.

update_dates([Link|Rest]) ->
    ecouch:start(temporary,{?HOST,?PORT}),
    ecouch:doc_update(?DATABASE,erlang:binary_to_list(object:get_value(Link,"_id")),
        {obj, [
            {"_rev",object:get_value(Link,"_rev")},
            {"source",object:get_value(Link,"source")},
            {"destination",object:get_value(Link,"destination")},
            {"rel",object:get_value(Link,"rel")},
            {"date_updated",erlang:list_to_binary(es_util:timestamp_now())}
        ]}),
    update_dates(Rest);

update_dates([]) ->
    ok.

test_add_link(Source,Destination,Rel) ->
    test_add_link(Source,Destination,Rel,false).

test_add_link(Source,Destination,Rel,true) ->
    test_add_link(Source,Destination,Rel,false),
    test_add_link(Destination,Source,Rel,false);

test_add_link(Destination,Source,Rel,false) ->
    ecouch:start(temporary,{?HOST,?PORT}),
    ecouch:doc_create(?DATABASE, 
        {obj, [
            {"source",erlang:list_to_binary(Source)},
            {"destination",erlang:list_to_binary(Destination)},
            {"rel",erlang:list_to_binary(Rel)},
            {"date_updated",erlang:list_to_binary(es_util:timestamp_now())}
        ]}).

get_identity(MeUrl) ->
    View = "_view/identity/get/?startkey=[\""++MeUrl++"\",0]&endkey=[\""++MeUrl++"\",2]",
    ecouch:start(temporary,{?HOST,?PORT}),
    Doc = ecouch:doc_get(?DATABASE,View),
    case Doc of
        {ok, Obj} -> 
            Rows = object:get_value(Obj,"rows"),
            {OutLinks, InLinks} = split(Rows),
            [MeUrl|intersection(OutLinks,InLinks)];
        Other ->
            {error, dont_know_why}
    end.

split(Rows) ->
    split(Rows, [], []).

split([], FirstList, SecondList) ->
    {FirstList, SecondList};

split([Head|Rest], FirstList, SecondList) ->
    Key = object:get_value(Head, "key"),
    case Key of
        [Url, 0|_] -> split(Rest, [erlang:binary_to_list(object:get_value(Head, "value"))|FirstList], SecondList);
        [Url, 1|_] -> split(Rest, FirstList, [erlang:binary_to_list(object:get_value(Head, "value"))|SecondList]);
        Other -> {error, malformed_key}
    end.

intersection(FirstList, SecondList) ->
    intersection(FirstList, SecondList, []).

intersection([], SecondList, ReturnList) ->
    ReturnList;

intersection([Head|Rest], SecondList, ReturnList)->
    case contains(Head, SecondList) of
        true -> intersection(Rest, SecondList, [Head|ReturnList]);
        false -> intersection(Rest, SecondList, ReturnList)
    end.

contains(Test, []) ->
    false;

contains(Test, [Head|Rest]) ->
    case Test =:= Head of
        true -> true;
        false -> contains(Test, Rest)
    end.

test() -> true.

add_links(MeUrl, Links)->
    View = "_view/links/get/?key=\""++MeUrl++"\"",
    ecouch:start(temporary,{?HOST,?PORT}),
    Doc = ecouch:doc_get(?DATABASE,View),
    case Doc of
        {ok,Obj} -> 
            Rows = object:get_value(Obj,"rows"),
            OldLinks = object:get_value_from_list(Rows,"value"),
            OutOfDateLinks = update_or_add_links(OldLinks, Links),
            delete_links(OutOfDateLinks);
        {error, Reason} ->
            {error, can_not_retrieve_links}
    end.

update_or_add_links(OldLinks, []) ->
    OldLinks;

update_or_add_links(OldLinks, [Link|Rest]) ->
    update_or_add_links(update_or_add_link(OldLinks, Link), Rest).

update_or_add_link(OldLinks, Link) ->
    update_or_add_link(OldLinks, Link, []).

update_or_add_link([], {Source, Destination, Rel}, LeftOverLinks) ->
    add_link(Source, Destination, Rel),
    LeftOverLinks;

update_or_add_link([OldLink|Rest], {Source, Destination, Rel}, LeftOverLinks) ->
    OldDestination = erlang:binary_to_list(object:get_value(OldLink, "destination")),
    OldSource = erlang:binary_to_list(object:get_value(OldLink, "source")),
    OldRel = erlang:binary_to_list(object:get_value(OldLink, "rel")),
    if
        OldDestination =:= Destination,
        OldSource =:= Source,
        OldRel =:= Rel ->
            LeftOverLinks ++ Rest;
        true ->
            update_or_add_link(Rest, {Source, Destination, Rel}, [OldLink|LeftOverLinks])
    end.

add_link(Source,Destination,Rel) ->
    ecouch:start(temporary,{?HOST,?PORT}),
    ecouch:doc_create(?DATABASE, 
        {obj, [
            {"source",erlang:list_to_binary(Source)},
            {"destination",erlang:list_to_binary(Destination)},
            {"rel",erlang:list_to_binary(Rel)},
            {"date_updated",erlang:list_to_binary(es_util:timestamp_now())}
        ]}).

delete_links([]) ->
    ok;
delete_links([Link|Rest]) ->        
    ecouch:start(temporary,{?HOST,?PORT}),
    ecouch:doc_delete(?DATABASE, erlang:binary_to_list(object:get_value(Link,"_id")), erlang:binary_to_list(object:get_value(Link,"_rev"))),
    delete_links(Rest).